home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / security / portmap_2.shar / pmap_check.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-06  |  6.3 KB  |  250 lines

  1.  /*
  2.   * pmap_check - additional portmap security.
  3.   * 
  4.   * Always reject non-local requests to update the portmapper tables.
  5.   * 
  6.   * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
  7.   * requests would appear to come from the local system, and nfs export
  8.   * restrictions could be bypassed.
  9.   * 
  10.   * Refuse to forward requests to the nfsd process.
  11.   * 
  12.   * Refuse to forward requests to NIS (YP) daemons; The only exception is the
  13.   * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
  14.   * contact with the NIS server.
  15.   * 
  16.   * Always allocate an unprivileged port when forwarding a request.
  17.   * 
  18.   * If compiled with -DCHECK_PORT, require that requests to register or
  19.   * unregister a privileged port come from a privileged port. This makes it
  20.   * more difficult to replace a critical service by a trojan.
  21.   * 
  22.   * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
  23.   * authorized by the /etc/hosts.{allow,deny} files. The local system is
  24.   * always treated as an authorized host. Access control is based on IP
  25.   * addresses only; attempts to map an address to a host name might cause the
  26.   * portmapper to hang.
  27.   * 
  28.   * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
  29.   * Computing Science, Eindhoven University of Technology, The Netherlands.
  30.   */
  31.  
  32. #ifndef lint
  33. static char sccsid[] = "@(#) pmap_check.c 1.2 92/07/06 19:53:32";
  34. #endif
  35.  
  36. #include <rpc/rpc.h>
  37. #include <rpc/pmap_prot.h>
  38. #include <syslog.h>
  39. #include <netdb.h>
  40. #include <sys/signal.h>
  41. #ifdef SYSV40
  42. #include <netinet/in.h>
  43. #include <rpc/rpcent.h>
  44. #endif
  45.  
  46. extern char *inet_ntoa();
  47.  
  48. #include "pmap_check.h"
  49.  
  50. /* Explicit #defines in case the include files are not available. */
  51.  
  52. #define NFSPROG        ((u_long) 100003)
  53. #define MOUNTPROG    ((u_long) 100005)
  54. #define    YPXPROG        ((u_long) 100069)
  55. #define YPPROG          ((u_long) 100004)
  56. #define YPPROC_DOMAIN_NONACK ((u_long) 2)
  57. #define MOUNTPROC_MNT    ((u_long) 1)
  58.  
  59. static void logit();
  60. static void toggle_verboselog();
  61. static int verboselog = 0;
  62.  
  63. /* A handful of macros for "readability". */
  64.  
  65. #define    legal_host(a) \
  66.   (from_local(a) || hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), ""))
  67.  
  68. #define    legal_port(a,p) \
  69.   (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
  70.  
  71. #define log_bad_port(addr, proc, prog) \
  72.   logit(LOG_ERR, addr, proc, prog, ": request from unprivileged port")
  73.  
  74. #define log_bad_host(addr, proc, prog) \
  75.   logit(LOG_ERR, addr, proc, prog, ": request from unauthorized host")
  76.  
  77. #define log_bad_owner(addr, proc, prog) \
  78.   logit(LOG_ERR, addr, proc, prog, ": request from non-local host")
  79.  
  80. #define    log_no_forward(addr, proc, prog) \
  81.   logit(LOG_ERR, addr, proc, prog, ": request not forwarded")
  82.  
  83. #define log_client(addr, proc, prog) \
  84.   logit(LOG_INFO, addr, proc, prog, "")
  85.  
  86. /* check_startup - additional startup code */
  87.  
  88. void    check_startup()
  89. {
  90.  
  91.     /*
  92.      * Give up root privileges so that we can never allocate a privileged
  93.      * port when forwarding an rpc request.
  94.      */
  95.     if (setuid(1) == -1) {
  96.     syslog(LOG_ERR, "setuid(1) failed: %m");
  97.     exit(1);
  98.     }
  99.     (void) signal(SIGINT, toggle_verboselog);
  100. }
  101.  
  102. /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
  103.  
  104. check_default(addr, proc, prog)
  105. struct sockaddr_in *addr;
  106. u_long  proc;
  107. u_long  prog;
  108. {
  109. #ifdef HOSTS_ACCESS
  110.     if (!legal_host(addr)) {
  111.     log_bad_host(addr, proc, prog);
  112.     return (FALSE);
  113.     }
  114. #endif
  115.     if (verboselog)
  116.     log_client(addr, proc, prog);
  117.     return (TRUE);
  118. }
  119.  
  120. /* check_privileged_port - additional checks for privileged-port updates */
  121.  
  122. check_privileged_port(addr, proc, prog, port)
  123. struct sockaddr_in *addr;
  124. u_long  proc;
  125. u_long  prog;
  126. u_long  port;
  127. {
  128. #ifdef CHECK_PORT
  129.     if (!legal_port(addr, port)) {
  130.     log_bad_port(addr, proc, prog);
  131.     return (FALSE);
  132.     }
  133. #endif
  134.     return (TRUE);
  135. }
  136.  
  137. /* check_setunset - additional checks for update requests */
  138.  
  139. check_setunset(addr, proc, prog, port)
  140. struct sockaddr_in *addr;
  141. u_long  proc;
  142. u_long  prog;
  143. u_long  port;
  144. {
  145.     if (!from_local(addr)) {
  146.     log_bad_owner(addr, proc, prog);
  147.     return (FALSE);
  148.     }
  149.     if (port && !check_privileged_port(addr, proc, prog, port))
  150.     return (FALSE);
  151.     if (verboselog)
  152.     log_client(addr, proc, prog);
  153.     return (TRUE);
  154. }
  155.  
  156. /* check_callit - additional checks for forwarded requests */
  157.  
  158. check_callit(addr, proc, prog, aproc)
  159. struct sockaddr_in *addr;
  160. u_long  proc;
  161. u_long  prog;
  162. u_long  aproc;
  163. {
  164. #ifdef HOSTS_ACCESS
  165.     if (!legal_host(addr)) {
  166.     log_bad_host(addr, proc, prog);
  167.     return (FALSE);
  168.     }
  169. #endif
  170.     if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
  171.     (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
  172.     (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
  173.     log_no_forward(addr, proc, prog);
  174.     return (FALSE);
  175.     }
  176.     if (verboselog)
  177.     log_client(addr, proc, prog);
  178.     return (TRUE);
  179. }
  180.  
  181. /* toggle_verboselog - toggle verbose logging flag */
  182.  
  183. static void toggle_verboselog(sig)
  184. int     sig;
  185. {
  186.     (void) signal(sig, toggle_verboselog);
  187.     verboselog = !verboselog;
  188. }
  189.  
  190. /* logit - report events of interest via the syslog daemon */
  191.  
  192. static void logit(severity, addr, procnum, prognum, text)
  193. int     severity;
  194. struct sockaddr_in *addr;
  195. u_long  procnum;
  196. u_long  prognum;
  197. char   *text;
  198. {
  199.     char   *procname;
  200.     char    procbuf[4 * sizeof(u_long)];
  201.     char   *progname;
  202.     char    progbuf[4 * sizeof(u_long)];
  203.     struct rpcent *rpc;
  204.     struct proc_map {
  205.     u_long  code;
  206.     char   *proc;
  207.     };
  208.     struct proc_map *procp;
  209.     static struct proc_map procmap[] = {
  210.     PMAPPROC_CALLIT, "callit",
  211.     PMAPPROC_DUMP, "dump",
  212.     PMAPPROC_GETPORT, "getport",
  213.     PMAPPROC_NULL, "null",
  214.     PMAPPROC_SET, "set",
  215.     PMAPPROC_UNSET, "unset",
  216.     0, 0,
  217.     };
  218.  
  219.     /*
  220.      * Fork off a process or the portmap daemon might hang while
  221.      * getrpcbynumber() or syslog() does its thing.
  222.      */
  223.  
  224.     if (fork() == 0) {
  225.  
  226.     /* Try to map program number to name. */
  227.  
  228.     if (prognum == 0) {
  229.         progname = "";
  230.     } else if (rpc = getrpcbynumber((int) prognum)) {
  231.         progname = rpc->r_name;
  232.     } else {
  233.         sprintf(progname = progbuf, "%lu", prognum);
  234.     }
  235.  
  236.     /* Try to map procedure number to name. */
  237.  
  238.     for (procp = procmap; procp->proc && procp->code != procnum; procp++)
  239.          /* void */ ;
  240.     if ((procname = procp->proc) == 0)
  241.         sprintf(procname = procbuf, "%lu", (u_long) procnum);
  242.  
  243.     /* Write syslog record. */
  244.  
  245.     syslog(severity, "connect from %s to %s(%s)%s",
  246.            inet_ntoa(addr->sin_addr), procname, progname, text);
  247.     exit(0);
  248.     }
  249. }
  250.